
import VNode from "../../vnode";
import { getObjectValue } from "../../utils/ObjectUtils";

/**
 * v-for的原理是：
 * 移除掉原来带有v-for的节点，然后创建一个虚拟节点（虚拟节点中的data就是v-for中要循环的属性）追加到父节点，虚拟节点中包含v-for的指令
 * 在虚拟节点下循环添加子节点并给子节点设置自定义env属性
 * 
 * @param {*} vm 
 * @param {*} node 当前vnode是带有v-for的节点，需要删除掉并且追加一个空的文本节点
 * @param {*} parent 
 * @param {*} dir 
 */
export function VFOR(vm, ele, parent, instruction) {
    // 创建虚拟节点
    let vnode = new VNode(ele.nodeName, ele, [], '', getVirtualNodeData(instruction)[1], parent, 0, '')
    vnode.instructions = instruction
    // 移除掉原来带有v-for的节点
    parent.ele.removeChild(ele)
    // 追加到父节点一个空的文本节点
    parent.ele.appendChild(document.createTextNode(''))
    // 分析v-for中的数据（创建子节点，并设置环境变量）
    analyserInstruction(vm, vnode, instruction, parent)    
    return vnode
}

/**
 * 获取虚拟节点数据
 * @param {*} instruction 
 * @returns 
 */
function getVirtualNodeData(instruction) {
    // 去掉两边空格后根据空格分割
    let data = instruction.trim().split(' in ')
    if(data.length != 2) {
        throw new Error('v-for指令错误')
    }
    return data
}



/**
 * 分析v-for数据，创建真实子节点，并给子节点设置自定义env属性
 * @param {*} vm 
 * @param {*} vnode 
 * @param {*} data 
 */
function analyserInstruction(vm, vnode, instruction, parent) {
    const dataSet = getVirtualNodeData(instruction)
    // 获取要循环的数据
    const dataList = getObjectValue(vm, dataSet[1])
    if(!dataSet) {
        throw new Error("Error: v-for指令遍历的数据不存在")
    }
    // 循环数据
    for(let i = 0; i < dataList.length; i++) {
        // 创建子节点
        let childNode = document.createElement(vnode.tag)
        // 设置html
        childNode.innerHTML = vnode.ele.innerHTML
        childNode.setAttribute("class", vnode.ele.getAttribute("class"))
        // 获取env
        const env = analyserKV(dataList[i], dataSet[0], i)
        // 设置自定义env属性
        childNode.setAttribute('env', JSON.stringify(env))
        // 追加到父节点
        parent.ele.appendChild(childNode)
    }
}

/**
 * 生成env
 * @param {*} data 当前data
 * @param {*} key （item, index） || (item) || item
 * @param {*} index 当前索引
 */
function analyserKV(data, instructions, index) {
    // 如果指令两边有小括号的话去掉指令两边的小括号
    instructions = instructions.trim().replace(/^\(|\)$/g, '')
    // 根据逗号分割
    const instruction = instructions.split(',')
    // 生成env
    const result = {}
    if(instruction.lenght == 0) {
        throw new Error('v-for指令错误')
    }
    if(instruction.length >= 1) {
        result[instruction[0]] = data
    }
    if(instruction.length >= 2) {
        result[instruction[1]] = index
    }
    return result
}


